//*********************************************************
//
//    Copyright (c) Microsoft. All rights reserved.
//    This code is licensed under the Apache License, Version 2.0.
//    THIS CODE IS PROVIDED *AS IS* WITHOUT WARRANTY OF
//    ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING ANY
//    IMPLIED WARRANTIES OF FITNESS FOR A PARTICULAR
//    PURPOSE, MERCHANTABILITY, OR NON-INFRINGEMENT.
//
//*********************************************************

namespace Microsoft.Research.ScientificWorkflow.WebClient.Common
{
    using System;
    using System.Collections.Generic;
    using System.Collections.ObjectModel;
    using System.Linq;
    using Common;
    using Microsoft.Research.ScientificWorkflow.TridentModelSL;
    using System.Globalization;
    using Microsoft.Research.ScientificWorkflow.WorkflowApplicationCommonSL;
    using service = Microsoft.Research.ScientificWorkflow.TridentSilverlightService;
    using System.ServiceModel;
    using Microsoft.Research.ScientificWorkflow;

    /// <summary>
    /// Holds the regitry related implementations.
    /// </summary>
    public static class RegistryService
    {
        #region Events

        public static event System.EventHandler<GetWorkflowCategoriesCompletedEventArgs> GetWorkflowCategoriesCompleted;
        public static event System.EventHandler<LoadUserCompletedEventArgs> LoadUserCompleted;
        public static event System.EventHandler<GetMyWorkflowsForUserCompletedEventArgs> GetMyWorkflowsForUserCompleted;
        public static event System.EventHandler<GetWorkflowByIdCompletedEventArgs> GetWorkflowByIdCompleted;
        public static event System.EventHandler<GetAllUsersMyWorkflowsCompletedEventArgs> GetAllUsersMyWorkflowsCompleted;
        public static event System.EventHandler<GetAllSharedWorkflowsForCurrentUserCompletedEventArgs> GetAllSharedWorkflowsForCurrentUserCompleted;
        public static event System.EventHandler<ExecuteWFOnMachineCompletedEventArgs> ExecuteWFOnMachineCompleted;
        public static event System.EventHandler<CompletedEventArgs> TerminateJobCompleted;
        public static event System.EventHandler<GetOutputsCompletedEventArgs> GetOutputsCompleted;
        public static event System.EventHandler<GetJobDetailsCompletedEventArgs> GetJobDetailsCompleted;

        #endregion

        #region Properties
        private static service.TridentServiceClient service;

        /// <summary>
        /// Gets the web service proxy.
        /// </summary>
        /// <value>The web service proxy.</value>
        public static service.TridentServiceClient WebServiceProxy
        {
            get
            {
                return service;
            }
        }

        #endregion

        /// <summary>
        /// Initializes the specified service point.
        /// </summary>
        /// <param name="servicePoint">The service point.</param>
        public static void Initialize(Uri servicePoint)
        {
            UriBuilder uriDL = new UriBuilder(servicePoint);
            uriDL.Path += "/TridentService.svc";

            EndpointAddress address = new EndpointAddress(uriDL.Uri);
            BasicHttpBinding binding = new BasicHttpBinding();
            service = new service.TridentServiceClient(binding, address);

            RegistryService.WebServiceProxy.GetWorkflowCategoriesCompleted += new EventHandler<service.GetWorkflowCategoriesCompletedEventArgs>(OnGetWorkflowCategoriesCompleted);
            RegistryService.WebServiceProxy.LoadUserCompleted += new EventHandler<service.LoadUserCompletedEventArgs>(OnLoadUserCompleted);
            RegistryService.WebServiceProxy.GetMyWorkflowsForUserCompleted += new EventHandler<service.GetMyWorkflowsForUserCompletedEventArgs>(OnGetMyWorkflowsForUserCompleted);
            RegistryService.WebServiceProxy.GetWorkflowByIdCompleted += new EventHandler<service.GetWorkflowByIdCompletedEventArgs>(OnGetWorkflowByIdCompleted);
            RegistryService.WebServiceProxy.GetAllUsersMyWorkflowsCompleted += new EventHandler<service.GetAllUsersMyWorkflowsCompletedEventArgs>(OnGetAllUsersMyWorkflowsCompleted);
            RegistryService.WebServiceProxy.GetAllSharedWorkflowsForCurrentUserCompleted += new EventHandler<service.GetAllSharedWorkflowsForCurrentUserCompletedEventArgs>(OnGetAllSharedWorkflowsForCurrentUserCompleted);
            RegistryService.WebServiceProxy.ExecuteWorkflowCompleted += new EventHandler<service.ExecuteWorkflowCompletedEventArgs>(OnExecuteWorkflowCompleted);
            RegistryService.WebServiceProxy.TerminateJobCompleted += new EventHandler<System.ComponentModel.AsyncCompletedEventArgs>(OnTerminateJobCompleted);
            RegistryService.WebServiceProxy.GetOutputsCompleted += new EventHandler<service.GetOutputsCompletedEventArgs>(OnGetOutputsCompleted);
            RegistryService.WebServiceProxy.GetJobDetailsCompleted += new EventHandler<service.GetJobDetailsCompletedEventArgs>(OnGetJobDetailsCompleted);
        }

        #region Async Methods

        /// <summary>
        /// Loads the user async.
        /// </summary>
        /// <param name="userName">Name of the user.</param>
        public static void LoadUserAsync(string userName)
        {
            RegistryService.WebServiceProxy.LoadUserAsync(userName);
        }

        /// <summary>
        /// Gets the workflow categories async.
        /// </summary>
        /// <param name="user">The user.</param>
        public static void GetWorkflowCategoriesAsync(UserModel user)
        {
            RegistryService.WebServiceProxy.GetWorkflowCategoriesAsync(user.ToNetwork());
        }

        /// <summary>
        /// Gets my workflows for user async.
        /// </summary>
        /// <param name="user">The user.</param>
        public static void GetMyWorkflowsForUserAsync(UserModel user)
        {
            RegistryService.WebServiceProxy.GetMyWorkflowsForUserAsync(user.ToNetwork());
        }

        /// <summary>
        /// Gets all users my workflows async.
        /// </summary>
        /// <param name="currentUser">The current user.</param>
        public static void GetAllUsersMyWorkflowsAsync(UserModel currentUser)
        {
            RegistryService.WebServiceProxy.GetAllUsersMyWorkflowsAsync(currentUser.ToNetwork());
        }

        /// <summary>
        /// Gets all shared workflows for current user async.
        /// </summary>
        /// <param name="currentUser">The current user.</param>
        public static void GetAllSharedWorkflowsForCurrentUserAsync(UserModel currentUser)
        {
            RegistryService.WebServiceProxy.GetAllSharedWorkflowsForCurrentUserAsync(currentUser.ToNetwork());
        }

        /// <summary>
        /// Executes the WF on machine async.
        /// </summary>
        /// <param name="jobDetails">The job details.</param>
        /// <param name="scheduledUser">The scheduled user.</param>
        public static void ExecuteWFOnMachineAsync(JobDescriptionModel jobDetails, UserModel scheduledUser)
        {
            RegistryService.WebServiceProxy.ExecuteWorkflowAsync(jobDetails.ToNetwork(), scheduledUser.ToNetwork());
        }

        /// <summary>
        /// Terminates the job async.
        /// </summary>
        /// <param name="jobId">The job id.</param>
        /// <param name="user">The user.</param>
        public static void TerminateJobAsync(Guid jobId, UserModel user)
        {
            RegistryService.WebServiceProxy.TerminateJobAsync(jobId, user.ToNetwork());
        }

        /// <summary>
        /// Gets the outputs async.
        /// </summary>
        /// <param name="jobId">The job id.</param>
        public static void GetOutputsAsync(Guid jobId)
        {
            RegistryService.WebServiceProxy.GetOutputsAsync(jobId);
        }

        /// <summary>
        /// Gets the workflow by id async.
        /// </summary>
        /// <param name="wfId">The wf id.</param>
        public static void GetWorkflowByIdAsync(Guid workflowId)
        {
            RegistryService.WebServiceProxy.GetWorkflowByIdAsync(workflowId);
        }

        /// <summary>
        /// Gets the job details async.
        /// </summary>
        /// <param name="jobId">The job id.</param>
        public static void GetJobDetailsAsync(Guid jobId)
        {
            RegistryService.WebServiceProxy.GetJobDetailsAsync(jobId);
        }

        #endregion

        #region Completed Event handlers

        /// <summary>
        /// Called when [get workflow categories completed].
        /// </summary>
        /// <param name="sender">The sender.</param>
        /// <param name="e">The <see cref="Microsoft.Research.ScientificWorkflow.TridentSilverlightService.GetWorkflowCategoriesCompletedEventArgs"/> instance containing the event data.</param>
        private static void OnGetWorkflowCategoriesCompleted(
            object sender,
            service.GetWorkflowCategoriesCompletedEventArgs e)
        {
            GetWorkflowCategoriesCompletedEventArgs completedEventArgs = new GetWorkflowCategoriesCompletedEventArgs(e.UserState);

            if (e.Error == null && e.Result != null)
            {
                List<CategoryModel> categories = new List<CategoryModel>();
                e.Result.ForEach(child => categories.Add(new CategoryModel(child)));

                completedEventArgs.Categories = categories;
            }
            else if (e.Error != null)
            {
                completedEventArgs.Error = e.Error;
            }

            if (GetWorkflowCategoriesCompleted != null)
            {
                GetWorkflowCategoriesCompleted.Invoke(null, completedEventArgs);
            }
        }

        /// <summary>
        /// Called when [load user completed].
        /// </summary>
        /// <param name="sender">The sender.</param>
        /// <param name="e">The <see cref="Microsoft.Research.ScientificWorkflow.TridentSilverlightService.LoadUserCompletedEventArgs"/> instance containing the event data.</param>
        private static void OnLoadUserCompleted(
            object sender,
            service.LoadUserCompletedEventArgs e)
        {
            LoadUserCompletedEventArgs completedEventArgs = new LoadUserCompletedEventArgs(e.UserState);

            if (e.Error == null && e.Result != null)
            {
                completedEventArgs.User = new UserModel(e.Result);
            }
            else if (e.Error != null)
            {
                completedEventArgs.Error = e.Error;
            }

            if (LoadUserCompleted != null)
            {
                LoadUserCompleted.Invoke(null, completedEventArgs);
            }
        }

        /// <summary>
        /// Called when [get my workflows for user completed].
        /// </summary>
        /// <param name="sender">The sender.</param>
        /// <param name="e">The <see cref="Microsoft.Research.ScientificWorkflow.TridentSilverlightService.GetMyWorkflowsForUserCompletedEventArgs"/> instance containing the event data.</param>
        private static void OnGetMyWorkflowsForUserCompleted(
            object sender,
            service.GetMyWorkflowsForUserCompletedEventArgs e)
        {
            GetMyWorkflowsForUserCompletedEventArgs completedEventArgs = new GetMyWorkflowsForUserCompletedEventArgs(e.UserState);

            if (e.Error == null && e.Result != null)
            {
                List<CategoryModel> categories = new List<CategoryModel>();
                e.Result.ForEach(child => categories.Add(new CategoryModel(child)));

                completedEventArgs.Categories = categories;
            }
            else if (e.Error != null)
            {
                completedEventArgs.Error = e.Error;
            }

            if (GetMyWorkflowsForUserCompleted != null)
            {
                GetMyWorkflowsForUserCompleted.Invoke(null, completedEventArgs);
            }
        }

        /// <summary>
        /// Called when [get all users my workflows completed].
        /// </summary>
        /// <param name="sender">The sender.</param>
        /// <param name="e">The <see cref="Microsoft.Research.ScientificWorkflow.TridentSilverlightService.GetAllUsersMyWorkflowsCompletedEventArgs"/> instance containing the event data.</param>
        private static void OnGetAllUsersMyWorkflowsCompleted(
            object sender,
            service.GetAllUsersMyWorkflowsCompletedEventArgs e)
        {
            GetAllUsersMyWorkflowsCompletedEventArgs completedEventArgs = new GetAllUsersMyWorkflowsCompletedEventArgs(e.UserState);

            if (e.Error == null && e.Result != null)
            {
                List<CategoryModel> categories = new List<CategoryModel>();
                e.Result.ForEach(child => categories.Add(new CategoryModel(child)));

                completedEventArgs.Categories = categories;
            }
            else if (e.Error != null)
            {
                completedEventArgs.Error = e.Error;
            }

            if (GetAllUsersMyWorkflowsCompleted != null)
            {
                GetAllUsersMyWorkflowsCompleted.Invoke(null, completedEventArgs);
            }
        }

        /// <summary>
        /// Called when [get workflow by id completed].
        /// </summary>
        /// <param name="sender">The sender.</param>
        /// <param name="e">The <see cref="Microsoft.Research.ScientificWorkflow.TridentSilverlightService.GetWorkflowByIdCompletedEventArgs"/> instance containing the event data.</param>
        private static void OnGetWorkflowByIdCompleted(object sender, service.GetWorkflowByIdCompletedEventArgs e)
        {
            GetWorkflowByIdCompletedEventArgs args = new GetWorkflowByIdCompletedEventArgs();
            if (e.Error == null && e.Result != null)
            {
                args.WorkflowModel = new DetailedWorkflowModel(e.Result);
            }
            else if (e.Error != null)
            {
                args.Error = e.Error;
            }

            if (GetWorkflowByIdCompleted != null)
            {
                GetWorkflowByIdCompleted.Invoke(null, args);
            }
        }

        /// <summary>
        /// Called when [get all shared workflows for current user completed].
        /// </summary>
        /// <param name="sender">The sender.</param>
        /// <param name="e">The <see cref="Microsoft.Research.ScientificWorkflow.TridentSilverlightService.GetAllSharedWorkflowsForCurrentUserCompletedEventArgs"/> instance containing the event data.</param>
        private static void OnGetAllSharedWorkflowsForCurrentUserCompleted(
            object sender,
            service.GetAllSharedWorkflowsForCurrentUserCompletedEventArgs e)
        {
            GetAllSharedWorkflowsForCurrentUserCompletedEventArgs completedEventArgs = new GetAllSharedWorkflowsForCurrentUserCompletedEventArgs(e.UserState);

            if (e.Error == null && e.Result != null)
            {
                List<CategoryModel> categories = new List<CategoryModel>();
                e.Result.ForEach(child => categories.Add(new CategoryModel(child)));

                completedEventArgs.Categories = categories;
            }
            else if (e.Error != null)
            {
                completedEventArgs.Error = e.Error;
            }

            if (GetAllSharedWorkflowsForCurrentUserCompleted != null)
            {
                GetAllSharedWorkflowsForCurrentUserCompleted.Invoke(null, completedEventArgs);
            }
        }

        /// <summary>
        /// Called when [execute workflow completed].
        /// </summary>
        /// <param name="sender">The sender.</param>
        /// <param name="e">The <see cref="Microsoft.Research.ScientificWorkflow.TridentSilverlightService.ExecuteWorkflowCompletedEventArgs"/> instance containing the event data.</param>
        private static void OnExecuteWorkflowCompleted(
            object sender,
            service.ExecuteWorkflowCompletedEventArgs e)
        {
            ExecuteWFOnMachineCompletedEventArgs completedEventArgs = new ExecuteWFOnMachineCompletedEventArgs(e.UserState);

            if (e.Error == null && e.Result != null)
            {
                completedEventArgs.Job = new JobDetails(e.Result);
            }
            else if (e.Error != null)
            {
                completedEventArgs.Error = e.Error;
            }

            if (ExecuteWFOnMachineCompleted != null)
            {
                ExecuteWFOnMachineCompleted.Invoke(null, completedEventArgs);
            }
        }

        /// <summary>
        /// Called when [terminate job completed].
        /// </summary>
        /// <param name="sender">The sender.</param>
        /// <param name="e">The <see cref="System.ComponentModel.AsyncCompletedEventArgs"/> instance containing the event data.</param>
        private static void OnTerminateJobCompleted(object sender, System.ComponentModel.AsyncCompletedEventArgs e)
        {
            CompletedEventArgs completedEventArgs = new CompletedEventArgs(e.UserState);

            if (e.Error != null)
            {
                completedEventArgs.Error = e.Error;
            }

            if (TerminateJobCompleted != null)
            {
                TerminateJobCompleted.Invoke(null, completedEventArgs);
            }
        }

        /// <summary>
        /// Called when [get outputs completed].
        /// </summary>
        /// <param name="sender">The sender.</param>
        /// <param name="e">The <see cref="Microsoft.Research.ScientificWorkflow.TridentSilverlightService.GetOutputsCompletedEventArgs"/> instance containing the event data.</param>
        private static void OnGetOutputsCompleted(object sender, service.GetOutputsCompletedEventArgs e)
        {
            GetOutputsCompletedEventArgs completedEventArgs = new GetOutputsCompletedEventArgs(e.UserState);

            if (e.Error == null && e.Result != null)
            {
                e.Result.ForEach(output => completedEventArgs.Outputs.Add(new WorkflowOutputModel(output)));
            }
            else if (e.Error != null)
            {
                completedEventArgs.Error = e.Error;
            }

            if (GetOutputsCompleted != null)
            {
                GetOutputsCompleted.Invoke(null, completedEventArgs);
            }
        }

        /// <summary>
        /// Called when [get job details completed].
        /// </summary>
        /// <param name="sender">The sender.</param>
        /// <param name="e">The <see cref="Microsoft.Research.ScientificWorkflow.TridentSilverlightService.GetJobDetailsCompletedEventArgs"/> instance containing the event data.</param>
        private static void OnGetJobDetailsCompleted(object sender, service.GetJobDetailsCompletedEventArgs e)
        {
            GetJobDetailsCompletedEventArgs completedEventArgs = new GetJobDetailsCompletedEventArgs(e.UserState);

            if (e.Error == null && e.Result != null)
            {
                completedEventArgs.Job = new JobDetails(e.Result);
            }
            else if (e.Error != null)
            {
                completedEventArgs.Error = e.Error;
            }

            if (GetJobDetailsCompleted != null)
            {
                GetJobDetailsCompleted.Invoke(null, completedEventArgs);
            }
        }
        #endregion
    }
}
